package com.citic.topview.system.security.manager;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.citic.topview.common.util.Servlets;
import com.citic.topview.system.util.PropertiesUtil;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

@Component
public class RedisSessionDao extends AbstractSessionDAO{

	private static Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);

	private static final String PRE = "topview-session:";
	
	private static final Long expire = PropertiesUtil.getLong("topview.redis.timeout");
	private static final Long expireGuan = PropertiesUtil.getLong("topview.guan.timeout");
	
    Cache<Serializable, Session> cache = CacheBuilder.newBuilder().expireAfterWrite(expireGuan, TimeUnit.SECONDS).build();
    Cache<Serializable, Session> updateCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).build();
    
	@Resource
    private RedisTemplate<String, Object> redisTemplate;
	
	@Override
	protected Serializable doCreate(Session session) {
		logger.info("RedisSessionDao --> doCreate: 创建");
		
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        cache.put(sessionId, session);
        redisTemplate.opsForValue().set(PRE + session.getId().toString(), session, expire, TimeUnit.SECONDS);
        return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		Session session = null;
		if(isStatic()) {
			session = cache.getIfPresent(sessionId);
			if (session != null){
				return session;
			}
			
			return null;
		}
		
		session = cache.getIfPresent(sessionId);
		if (session != null){
			return session;
		}
		
		logger.info("RedisSessionDao --> doReadSession: 读取");
		
		session = (Session) redisTemplate.opsForValue().get(PRE + sessionId.toString());
		
		return session;
	}
	
	@Override
	public void update(Session session) throws UnknownSessionException {
		if (session == null || session.getId() == null) {  
            return;
        }
		
		if(isStatic()) {
			return;
		}
		
		Boolean isChanged = null;
		if(session instanceof RedisSession) {
			RedisSession redisSession = (RedisSession)session;
			if(redisSession.isChanged() == false) { // 如果没有主要字段(除lastAccessTime以外其他字段)发生改变
				isChanged = false;
			}
			
			if (redisSession.isChanged() == true) { 
				isChanged = true;
				redisSession.setChanged(false); //如果没有返回 证明有调用 setAttribute往redis 放的时候永远设置为false
			}
    	}
		
		if(isChanged == false) {
	 		if(updateCache.getIfPresent(session.getId()) != null) {
				return;
			}
		}
 		
		logger.info("RedisSessionDao --> update: 更新");
		
        String key = PRE + session.getId().toString();
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().set(key, session);
        }
        
        cache.put(session.getId(), session);
        updateCache.put(session.getId(), session);
        
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
	}

	@Override
	public void delete(Session session) {
		if (session == null || session.getId() == null) {
			return;
		}
		
		logger.info("RedisSessionDao --> delete: 删除");
		
        redisTemplate.delete(PRE + session.getId().toString());
	}
	
	@Override
	public Collection<Session> getActiveSessions() {
		Set<Session> sessions = new HashSet<Session>();
        try {
            
        } catch (Exception e) {
            logger.error("get active sessions error.");
        }
        
        return sessions;
	}
	
	private boolean isStatic() {
		String uri = StringUtils.EMPTY;
		HttpServletRequest request = Servlets.getRequest();
		if (request != null){
			uri = request.getServletPath();
			if (Servlets.isStaticFile(uri)){ // 如果是静态文件，则不创建SESSION
		        return true;
			}
		}
		
		return false;
	}
}

/*@Component
public class RedisSessionDao extends EnterpriseCacheSessionDAO{

	private static Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
	
	private static final Long expire = PropertiesUtil.getLong("topview.redis.timeout");
	private static final Long expireGuan = PropertiesUtil.getLong("topview.redis.timeout");
	
    private static final String PRE = "topview-session:";
    Cache<Serializable, Session> cache = CacheBuilder.newBuilder().expireAfterWrite(expireGuan, TimeUnit.SECONDS).build();
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    
    public RedisSessionDao() {
        super();
    }

	@Override
	protected Serializable doCreate(Session session) {
		logger.info("RedisSessionDao --> doCreate: 创建");
		
		Serializable sessionId = super.doCreate(session);
		cache.put(sessionId, session);
        redisTemplate.opsForValue().set(PRE + session.getId().toString(), session, expire, TimeUnit.SECONDS);
        return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		Session session = null;
		if(isStatic()) {
			return null;
		}
		
		session = cache.getIfPresent(sessionId);
		if (session != null){
			return session;
		}
		
        session = (Session) redisTemplate.opsForValue().get(PRE + sessionId.toString());
        if(session != null) cache.put(sessionId, session);
        
		logger.info("RedisSessionDao --> doReadSession: 读取");
		
        return session;
	}

    @Override
    protected void doUpdate(Session session) {
		if (session == null || session.getId() == null) {  
            return;
        }
		
		if(isStatic()) {
			return;
		}
		
		if(session instanceof RedisSession) {
			RedisSession redisSession = (RedisSession)session;
			// 如果没有主要字段(除lastAccessTime以外其他字段)发生改变
			if (!redisSession.isChanged()) {
                return;
            }
            //如果没有返回 证明有调用 setAttribute往redis 放的时候永远设置为false
			redisSession.setChanged(false);
    	}
		
		logger.info("RedisSessionDao --> doUpdate: 更新");
		
        String key = PRE + session.getId().toString();
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().set(key, session);
            cache.put(session.getId(), session);
        }
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    protected void doDelete(Session session) {
		if (session == null || session.getId() == null) {
			return;
		}
		
		logger.info("RedisSessionDao --> doDelete: 删除");
		
        redisTemplate.delete(PRE + session.getId().toString());
    }

	@Override
	public Collection<Session> getActiveSessions() {
		return super.getActiveSessions();
	}
	
	private boolean isStatic() {
		String uri = StringUtils.EMPTY;
		HttpServletRequest request = Servlets.getRequest();
		if (request != null){
			uri = request.getServletPath();
			if (Servlets.isStaticFile(uri)){ // 如果是静态文件，则不创建SESSION
		        return true;
			}
		}
		
		return false;
	}
	
}*/
